package com.tbit.main.controller;


import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSONObject;
import com.tbit.common.entity.vo.MainLogAuditVo;
import com.tbit.main.common.JsonResult;
import com.tbit.main.constant.DistributedLock;
import com.tbit.main.constant.MapConstant;
import com.tbit.main.constant.RedisConstant;
import com.tbit.main.exception.BaseException;
import com.tbit.main.pojo.*;
import com.tbit.main.service.*;
import com.tbit.main.util.Assert;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.MapUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.serializer.SerializationException;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.Valid;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 调度记录
 *
 * @author Leon
 * 2019年1月23日 下午3:51:50
 */
@Slf4j
@RestController
@RequestMapping("/dispatchLog")
public class DispatchLogController {
    @Autowired
    private DispatchLogService dispatchLogService;
    @Autowired
    private TokenService tokenService;
    @Autowired
    private MachineService machineService;
    @Autowired
    private RedisService redisService;
    @Autowired
    private MachineOccupyService machineOccupyService;
    @Autowired
    private MachineBorrowService machineBorrowService;
    @Autowired
    private MachineStatusService machineStatusService;
    @Autowired
    private StockMachineService stockMachineService;

    /**
     * 调度
     */
    @RequestMapping("/dispatch")
    @DistributedLock(timeout = 60)
    public JsonResult dispatch(String token, String userCode, Integer parkPointId,
                               @RequestParam(value = "mapType", required = false) Integer mapType,
                               @RequestParam(value = "lon", required = false) Double lon,
                               @RequestParam(value = "lat", required = false) Double lat) throws Exception {
        AccountUser accountUserToken = tokenService.getAccount(token);

        if (mapType == null) {
            mapType = MapConstant.MAP_GOOGLE;
        }

        Assert.hasLength(userCode, "Machine.userCode.notNull");

        /**查询设备信息*/
        Machine machine = machineService.getByUseCode(userCode);
        if (machine == null) {
            throw new BaseException("Machine.notExist");
        }

        /**设备权限判断*/
        machineService.auth(accountUserToken.getAgents(), machine.getMachineId());

        /**是否是运维占用*/
        MachineOccupy machineOccupy = machineOccupyService.getByMachineId(machine.getMachineId());
        if (machineOccupy != null && !machineOccupy.getAccountUserId().equals(accountUserToken.getAccountUserId())) {
            throw new BaseException("WorkOrder.occupy.notOperate");
        }

        /**
         * 是否是运维占用
         *
         * 实时的运维占用是以由已落库的数量加上缓存调度中的数量
         * */
        String dispatchLogString = redisService.get(RedisConstant.REDIS_TER_BIKE_DISPATCH + machine.getMachineNO());
        DispatchLog dispatchLogCache = JSONObject.parseObject(dispatchLogString, DispatchLog.class);
        log.info("---------------------------------"+dispatchLogString);
        if (dispatchLogCache != null && !dispatchLogCache.getUserMainId().equals(accountUserToken.getAccountUserId())) {
            throw new BaseException("WorkOrder.occupy.notOperate");
        }

        /**是否是未出库车辆*/
        List<Integer> machineIds = new LinkedList<>();
        machineIds.add(machine.getMachineId());
        List<Integer> stockMachineIds = stockMachineService.getAccountIdByMachineId(machine.getAccountId(), machineIds);
        if (stockMachineIds != null && !stockMachineIds.isEmpty()) {
            throw new BaseException("StockMachine.is.operate");
        }

        DispatchLog dispatchLog = dispatchLogService.dispatch(accountUserToken, machine.getMachineNO(), parkPointId, lon, lat, mapType);

        return JsonResult.succ(dispatchLog);
    }

    /**
     * 批量开锁调度
     *
     * @param userCodes   车辆编号集合
     * @param token       鉴权秘钥
     * @param parkPointId 站点
     * @param mapType     地图类型
     * @param lon         经度
     * @param lat         纬度
     * @return
     */
    @RequestMapping("/dispatchByCodes")
    @DistributedLock(timeout = 60)
    public JsonResult dispatchByCodes(@RequestParam("userCodes") List<String> userCodes, String token, Integer parkPointId,
                                      @RequestParam(value = "mapType", required = false, defaultValue = "2") Integer mapType,
                                      @RequestParam(value = "lon", required = false) Double lon,
                                      @RequestParam(value = "lat", required = false) Double lat) throws Exception {
        AccountUser accountUser = tokenService.getAccount(token);

        userCodes = userCodes.stream().distinct().collect(Collectors.toList());

        List<Machine> machines = machineService.getByUserCodes(userCodes);

        Integer accountId = machines.get(0).getAccountId();
        List<Integer> machineIds = machines.stream().map(Machine::getMachineId).collect(Collectors.toList());
        List<Integer> stockMachineIds = stockMachineService.getAccountIdByMachineId(accountId, machineIds);
        if (stockMachineIds != null && !stockMachineIds.isEmpty()) {
            throw new BaseException("StockMachine.is.operate");
        }

        /**权限校验*/
        stockMachineService.checkBatch(machines, accountUser, userCodes);
        for (Machine machine : machines) {
            dispatchLogService.dispatch(accountUser, machine.getMachineNO(), parkPointId, lon, lat, mapType);
        }
        return JsonResult.succ();
    }

    /**
     * 批量调度
     */
    @RequestMapping("/dispatchBatch")
    // 分布式锁
    @DistributedLock(timeout = 60)
    public JsonResult dispatchBatch(String token, RequestParameter requestParameter) throws Exception {
        AccountUser accountUserToken = tokenService.getAccount(token);

        if (requestParameter.getMapType() == null) {
            requestParameter.setMapType(MapConstant.MAP_GOOGLE);
        }

        Assert.notNull(requestParameter.getUserCodes(), "Machine.userCode.notNull");

        dispatchLogService.dispatchBatch(accountUserToken, requestParameter.getUserCodes(), requestParameter.getParkPointId(), requestParameter.getLon(), requestParameter.getLat(), requestParameter.getMapType());

        return JsonResult.succ();
    }

    /**
     * 获取批量调度车辆编号
     */
    @RequestMapping("/getBatchUserCodePower")
    public JsonResult getBatchUserCodePower(String token) {
        AccountUser accountUser = tokenService.getAccount(token);
        List<String> userDispatchMachineCache = new LinkedList<>();
        String key = RedisConstant.REDIS_BATCH_DISPATCH + accountUser.getAccountUserId();
        try {
            userDispatchMachineCache = redisService.getList(key);
        } catch (SerializationException e) {
            redisService.del(key);
        }
        List<Map<String, Object>> faultOrAbnormalList = new LinkedList<>();
        List<Map<String, Object>> list = new LinkedList<>();
        if (CollUtil.isNotEmpty(userDispatchMachineCache)) {
            List<Machine> machines = machineService.getByUserCodes(userDispatchMachineCache);
            Map<String, Integer> machineMap = new HashMap<>();
            Map<Integer, Integer> machineBorrowMap = new HashMap<>();
            Map<Integer, Integer> machineStatuseMap = new HashMap<>();
            Map<Integer, Map<String, List<String>>> machineFaultAndAbnormalMap = new HashMap<>();
            if (CollUtil.isNotEmpty(machines)) {
                for (Machine machine : machines) {
                    machineMap.put(machine.getUserCode(), machine.getMachineId());
                }

                List<MachineBorrow> machineBorrows = machineBorrowService.getByMachineIds(machines.stream().map(Machine::getMachineId).collect(Collectors.toList()));
                for (MachineBorrow machine : machineBorrows) {
                    machineBorrowMap.put(machine.getMachineId(), 1);
                }

                List<MachineStatus> machineStatuses = machineStatusService.getByMachineIdBatch(machines.stream().map(Machine::getMachineId).collect(Collectors.toList()));
                for (MachineStatus machine : machineStatuses) {
                    machineStatuseMap.put(machine.getMachineId(), machine.getSocPercent());
                }
                //获取车辆异常、故障
                machineFaultAndAbnormalMap = machineService.getMachineFaultAndAbnormal(machines.stream().map(Machine::getMachineId).collect(Collectors.toList()));
            }

            for (String code : userDispatchMachineCache) {
                // 车辆不存在删除缓存
                if (!machineMap.containsKey(code)) {
                    dispatchLogService.delCache(code);
                } else {
                    Integer machine = machineMap.get(code);
                    Map<String, List<String>> faultAndAbnormalMap = machineFaultAndAbnormalMap.get(machineMap.get(code));
                    Map<String, Object> map = new HashMap<>();
                    map.put("userCode", code);
                    map.put("inUse", machineBorrowMap.get(machine) == null ? 0 : 1);
                    map.put("socPercent", machineStatuseMap.get(machine));
                    map.put("abnormal", MapUtils.isNotEmpty(faultAndAbnormalMap) ? faultAndAbnormalMap.get("abnormal") : null);
                    map.put("fault", MapUtils.isNotEmpty(faultAndAbnormalMap) ? faultAndAbnormalMap.get("fault") : null);
                    //故障或异常的车辆排在前面
                    if (Objects.nonNull(map.get("abnormal")) || Objects.nonNull(map.get("fault"))){
                        faultOrAbnormalList.add(map);
                    }else {
                        list.add(map);
                    }
                }
            }
        }
        //故障或异常的车辆排在前面
        faultOrAbnormalList.addAll(list);
        return JsonResult.succ(faultOrAbnormalList);
    }

    /**
     * 获取批量调度车辆编号
     */
    @RequestMapping("/getBatchUserCode")
    public JsonResult getBatchUserCode(String token) {
        AccountUser accountUser = tokenService.getAccount(token);
        List<String> userDispatchMachineCache = new LinkedList<>();
        try {
            userDispatchMachineCache = redisService.getList(RedisConstant.REDIS_BATCH_DISPATCH + accountUser.getAccountUserId());
        } catch (SerializationException e) {
            redisService.del(RedisConstant.REDIS_BATCH_DISPATCH + accountUser.getAccountUserId());
        }

        return JsonResult.succ(userDispatchMachineCache);
    }

    /**
     * 删除
     *
     * @param userCode
     */
    @RequestMapping("/DEL")
    public JsonResult del(String userCode) {

        Machine machine = machineService.getByUseCode(userCode);

        if (machine != null) {
            /**上锁*/
            dispatchLogService.dispatchLock(machine, "取消调度自动上锁");
        }

        dispatchLogService.delCache(userCode);

        return JsonResult.succ();
    }

    /**
     * 分组统计 调度状态
     */
    @RequestMapping("/groupByTime")
    public JsonResult groupByTime(String token, Integer accountId, String startTime, String endTime,
                                  @RequestParam(value = "state", required = false) Integer state,
                                  @RequestParam(value = "isValid", required = false) Integer isValid,
                                  @RequestParam(value = "regionId", required = false) List<Integer> regionId,
                                  @RequestParam(value = "machineType", required = false) Integer machineType) {
        AccountUser accountUserToken = tokenService.getAccount(token);
        Assert.hasLength(startTime, "System.startTime.notNull");
        Assert.hasLength(endTime, "System.endTime.notNull");
        Assert.notNull(accountId, "AccountUser.agentId.notNull");


        List<DispatchLogSta> moveLogStas = dispatchLogService.groupByTime(accountId, accountUserToken.getAccountUserType(),
                accountUserToken.getAccountUserId(), state, startTime, endTime, isValid, regionId, machineType);

        return JsonResult.succ(moveLogStas);
    }

    /**
     * 根据时间查询 调度状态
     */
    @RequestMapping("/getByTime")
    public JsonResult getByTime(Integer accountId, Integer userMainId, String startTime, String endTime,
                                @RequestParam(value = "userCode", required = false) String userCode,
                                @RequestParam(value = "state", required = false) Integer state,
                                @RequestParam(value = "isValid", required = false) Integer isValid,
                                @RequestParam(value = "regionId", required = false) List<Integer> regionId,
                                @RequestParam(value = "machineType", required = false) Integer machineType) {
        Assert.hasLength(startTime, "System.startTime.notNull");
        Assert.hasLength(endTime, "System.endTime.notNull");
        Assert.notNull(accountId, "AccountUser.agentId.notNull");


        List<DispatchLog> moveLogs = dispatchLogService.getByTime(accountId, userMainId, state, startTime, endTime, userCode, isValid, regionId, machineType);

        return JsonResult.succ(moveLogs);
    }

    /**
     * 根据id查询
     */
    @RequestMapping("/getById")
    public JsonResult getById(Integer dispatchLogId) {
        Assert.notNull(dispatchLogId, "Machine.move.id.notNull");

        DispatchLog dispatchLog = dispatchLogService.getById(dispatchLogId);

        return JsonResult.succ(dispatchLog);
    }

    /**
     * 更新
     */
    @RequestMapping("/update")
    public JsonResult<Object> update(@Valid MainLogAuditVo vo) {
        dispatchLogService.update(vo);
        return JsonResult.succ();
    }
}